package com.yeskery.nut.aop.handler;

import com.yeskery.nut.aop.DefaultProxyObjectContext;
import com.yeskery.nut.aop.ProxyObjectContext;
import com.yeskery.nut.aop.aspect.AspectAdvice;
import com.yeskery.nut.bean.ApplicationContext;
import com.yeskery.nut.bean.BaseApplicationContext;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 基于切面的代理方法处理器
 * @author Yeskery
 * 2023/8/7
 */
public class AspectProxyMethodHandler extends BaseInjectProxyMethodHandler {

    /** 代理对象上下文 */
    private ProxyObjectContext proxyObjectContext;

    /**
     * 基于切面的代理方法处理器
     * @param applicationContext 应用上下文
     */
    public AspectProxyMethodHandler(ApplicationContext applicationContext) {
        super(applicationContext);
    }

    /**
     * 获取代理对象上下文
     * @return 代理对象上下文
     */
    protected ProxyObjectContext getProxyObjectContext() {
        if (proxyObjectContext == null) {
            proxyObjectContext = ((BaseApplicationContext) getApplicationContext()).getProxyObjectContext();
        }
        return proxyObjectContext;
    }

    /**
     * 获取代理方法注解缓存map
     * @return 代理方法注解缓存map
     */
    protected Map<String, Collection<AspectAdvice>> getProxyMethodAspectCacheMap() {
        return ((DefaultProxyObjectContext) getProxyObjectContext()).getPoxyMethodAspectCacheMap();
    }

    /**
     * 追加切面代理对象
     * @param method 方法对象
     * @param annotationClass 要执行的切面注解类型
     * @param proxyMethodTargetList 代理对象集合
     */
    protected void appendAspectProxyTarget(Method method, Class<? extends Annotation> annotationClass, List<ProxyMethodTarget> proxyMethodTargetList) {
        Collection<AspectAdvice> aspectAdvices = getProxyMethodAspectCacheMap().get(method.toString());
        if (aspectAdvices != null && !aspectAdvices.isEmpty()) {
            for (AspectAdvice aspectAdvice : aspectAdvices) {
                if (annotationClass.isAssignableFrom(aspectAdvice.getAnnotation().getClass())) {
                    proxyMethodTargetList.add(new ProxyMethodTarget(aspectAdvice.getBeanName(), aspectAdvice.getBeanType(),
                            aspectAdvice.getMethod().getName(), getOrder(aspectAdvice.getAnnotation())));
                }
            }
        }
    }

    /**
     * 获取排序值
     * @param annotation 切面注解
     * @return 排序值
     */
    private static int getOrder(Annotation annotation) {
        try {
            Method method = annotation.getClass().getMethod("order");
            return (int) method.invoke(annotation);
        } catch (Exception e) {
            return 0;
        }
    }
}
